package com.viknix.threadpool.manager.http;

import com.viknix.threadpool.manager.http.factory.DefaultHttpClientFactory;
import com.viknix.threadpool.manager.http.factory.HttpClientFactory;
import com.viknix.threadpool.manager.server.dependence.util.ExceptionUtil;
import com.viknix.threadpool.manager.server.dependence.util.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @Author: Dongqi
 * @Date: 2021/11/22 10:57
 * @Version 1.0
 * @Description: Create a rest template to ensure that each custom client config and rest template are in one-to-one correspondence.
 */
public final class HttpClientBeanHolder {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientBeanHolder.class);

    private static final Map<String, TpmRestTemplate> SINGLETON_REST = new HashMap<String, TpmRestTemplate>(10);

    /**
     * key：factoryName，value：TpmAsyncRestTemplate
     * 缓存由不同工厂生产的 TpmAsyncRestTemplate
     */
    private static final Map<String, TpmAsyncRestTemplate> SINGLETON_ASYNC_REST = new HashMap<String, TpmAsyncRestTemplate>(
            10);

    private static final AtomicBoolean ALREADY_SHUTDOWN = new AtomicBoolean(false);

    static {
        ThreadUtils.addShutdownHook(new Runnable() {
            @Override
            public void run() {
                shutdown();
            }
        });
    }

    public static TpmRestTemplate getTpmRestTemplate() {
        return getTpmRestTemplate(new DefaultHttpClientFactory());
    }

    public static TpmRestTemplate getTpmRestTemplate(HttpClientFactory httpClientFactory) {
        if (httpClientFactory == null) {
            throw new NullPointerException("httpClientFactory is null");
        }
        String factoryName = httpClientFactory.getClass().getName();
        TpmRestTemplate tpmRestTemplate = SINGLETON_REST.get(factoryName);
        if (tpmRestTemplate == null) {
            synchronized (SINGLETON_REST) {
                tpmRestTemplate = SINGLETON_REST.get(factoryName);
                if (tpmRestTemplate != null) {
                    return tpmRestTemplate;
                }
                tpmRestTemplate = httpClientFactory.createTpmRestTemplate();
                SINGLETON_REST.put(factoryName, tpmRestTemplate);
            }
        }
        return tpmRestTemplate;
    }

    /**
     * 获取 TpmAsyncRestTemplate
     *
     * @return TpmAsyncRestTemplate
     */
    public static TpmAsyncRestTemplate getTpmAsyncRestTemplate() {
        return getTpmAsyncRestTemplate(new DefaultHttpClientFactory());
    }

    public static TpmAsyncRestTemplate getTpmAsyncRestTemplate(HttpClientFactory httpClientFactory) {
        if (httpClientFactory == null) {
            throw new NullPointerException("httpClientFactory is null");
        }
        String factoryName = httpClientFactory.getClass().getName();
        // 从 SINGLETON_ASYNC_REST 集合中获取 TpmAsyncRestTemplate
        TpmAsyncRestTemplate tpmAsyncRestTemplate = SINGLETON_ASYNC_REST.get(factoryName);
        if (tpmAsyncRestTemplate == null) {
            synchronized (SINGLETON_ASYNC_REST) {
                tpmAsyncRestTemplate = SINGLETON_ASYNC_REST.get(factoryName);
                if (tpmAsyncRestTemplate != null) {
                    return tpmAsyncRestTemplate;
                }
                // 通过 httpClientFactory 生产 TpmAsyncRestTemplate
                tpmAsyncRestTemplate = httpClientFactory.createTpmAsyncRestTemplate();
                // 注册到 SINGLETON_ASYNC_REST 中进行统一管理
                SINGLETON_ASYNC_REST.put(factoryName, tpmAsyncRestTemplate);
            }
        }
        return tpmAsyncRestTemplate;
    }

    /**
     * Shutdown common http client.
     */
    private static void shutdown() {
        if (!ALREADY_SHUTDOWN.compareAndSet(false, true)) {
            return;
        }
        LOGGER.warn("[HttpClientBeanHolder] Start destroying common HttpClient");
        try {
            shutdown(DefaultHttpClientFactory.class.getName());
        } catch (Exception ex) {
            LOGGER.error("An exception occurred when the common HTTP client was closed : {}", ExceptionUtil.getStackTrace(ex));
        }
        LOGGER.warn("[HttpClientBeanHolder] Destruction of the end");
    }

    /**
     * Shutdown http client holder and close remove template.
     *
     * @param className HttpClientFactory implement class name
     * @throws Exception ex
     */
    public static void shutdown(String className) throws Exception {
        shutdownTpmSyncRest(className);
        shutdownTpmAsyncRest(className);
    }

    /**
     * Shutdown sync http client holder and remove template.
     *
     * @param className HttpClientFactory implement class name
     * @throws Exception ex
     */
    public static void shutdownTpmSyncRest(String className) throws Exception {
        final TpmRestTemplate tpmRestTemplate = SINGLETON_REST.get(className);
        if (tpmRestTemplate != null) {
            tpmRestTemplate.close();
            SINGLETON_REST.remove(className);
        }
    }

    /**
     * Shutdown async http client holder and remove template.
     *
     * @param className HttpClientFactory implement class name
     * @throws Exception ex
     */
    public static void shutdownTpmAsyncRest(String className) throws Exception {
        final TpmAsyncRestTemplate tpmAsyncRestTemplate = SINGLETON_ASYNC_REST.get(className);
        if (tpmAsyncRestTemplate != null) {
            tpmAsyncRestTemplate.close();
            SINGLETON_ASYNC_REST.remove(className);
        }
    }
}
